package com.gitee.hermer.engine.jars.core.zipkin.interceptor;

import java.lang.reflect.Method;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import com.gitee.hermer.boot.jee.commons.log.UtilsContext;
import com.gitee.hermer.boot.jee.commons.reflect.ReflectUtils;

import brave.SpanCustomizer;
import brave.servlet.TracingFilter;
import brave.spring.webmvc.HandlerParser;

public class EngineZipkinSpanHandlerInterceptor extends UtilsContext implements HandlerInterceptor{

	/** Redefined from HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE added in Spring 3. */
	static final String BEST_MATCHING_PATTERN_ATTRIBUTE =
			"org.springframework.web.servlet.HandlerMapping.bestMatchingPattern";

	@Autowired(required = false)
	HandlerParser handlerParser = new HandlerParser();

	public EngineZipkinSpanHandlerInterceptor() { // hide the ctor so we can change later if needed
	}

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) {
		SpanCustomizer span = (SpanCustomizer) request.getAttribute(SpanCustomizer.class.getName());
		if (span != null) {
			setHttpRouteAttribute(request);
			try{
				Method method = HandlerParser.class.getDeclaredMethod("preHandle", HttpServletRequest.class,Object.class,SpanCustomizer.class);
				method.setAccessible(true);
				ReflectUtils.invoke(handlerParser, new Object[]{request, o, span}, method);
			}catch (Throwable e) {
				error(e.getMessage(),e);
			}
		}
		return true;
	}

	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) {
	}

	@Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
			Object handler, Exception ex) {
	}

	/**
	 * Sets the "http.route" attribute from {@link #BEST_MATCHING_PATTERN_ATTRIBUTE} so that the
	 * {@link TracingFilter} can read it.
	 */
	static void setHttpRouteAttribute(HttpServletRequest request) {
		Object httpRoute = request.getAttribute(BEST_MATCHING_PATTERN_ATTRIBUTE);
		request.setAttribute("http.route", httpRoute != null ? httpRoute.toString() : "");
	}

}
